import multiprocessing
from multiprocessing import Process
import psutil


class ProcessPoolManger(object):

    def __init__(self):
        self.processpool = MProcessPool()

    def set_pool_num(self, num):
        self.processpool = MProcessPool(num)

    def apply_process_pool(self, func, *args, **kwds):
        """
        同步执行进程池
        :return:
        """
        self.processpool.apply(func=func, args=args, kwds=kwds)

    def apply_async_process_pool(self, func, callback=None, *args, **kwds, ):
        """
              异步执行进程
        :param func:
        :param callback:  回调函数
        :param args:
        :param kwds:
        :return:
        """
        self.processpool.apply_async(func, args, kwds, callback)

    def map(self, func, argslist):
        """
        Pool类中的map方法，与内置的map函数用法行为基本一致，它会使进程阻塞直到返回结果。
        注意，虽然第二个参数是一个迭代器，但在实际使用中，必须在整个队列都就绪后，程序才会运行子进程
        :param func:
        :param argslist:
        :return:
        """
        self.processpool.map(func, argslist)

    def close(self):
        self.processpool.close()

    def join(self):
        """
        主进程阻塞等待子进程的退出，join方法必须在close或terminate之后使用。
        :return:
        """
        self.processpool.join()


class MPsutil():
    def __init__(self, pid):
        self.p = psutil.Process(pid)

    def get_bin(self):
        """
        获取进行bin的路径
        :return:
        """
        return self.p.exe()

    def get_cwd(self):
        """
        获取进程工作目录绝对路径
        """
        return self.p.cwd()

    def get_status(self):
        """
        进程的状态
        :return:
        """
        return self.p.status()

    def get_create_time(self):
        """
        进程创建的时间
        :return:
        """
        return self.p.create_time()

    def get_uids(self):
        """
        进程uid信息
        :return:
        """
        return self.p.uids()

    def get_gids(self):
        """
        进程gid信息
        :return:
        """
        return self.p.gids()

    def get_cpu_times(self):
        """
        进程CPU时间信息，包括user、system两个CPU时间
        :return:
        """
        return self.p.cpu_times()

    def get_cpu_affinity(self):
        """
        获取进程cpu的亲和度
        :return:
        """
        return self.p.cpu_affinity()

    def get_memory_percent(self):
        """
        获取进程内存利用率
        :return:
        """
        return self.p.memory_percent()

    def get_memory_info(self):
        """
        进程内存rss、vms信息
        :return:
        """
        return self.p.memory_info()

    def get_io_counters(self):
        """
        进程IO信息，包括读写IO数及字节数
        :return:
        """
        return self.p.io_counters()

    def get_connections(self):
        """
        获取打开进程socket的namedutples列表，包括fs、family、laddr等信息
        :return:
        """
        return self.p.connections()

    def get_num_threads(self):
        """
        进程开启的线程数
        :return:
        """
        return self.p.num_threads()


class MProcessPool(multiprocessing.Pool):
    def __init__(self, processes=None, initializer=None, initargs=(),
                 maxtasksperchild=None, context=None):
        super().__init__(processes, initializer, initargs,
                         maxtasksperchild, context)


class ProcessManager(Process):
    """
    定义进程类 继承进程 所有进程为该类
    """

    def __init__(self, work_queue=None, result_queue=None, group=None, target=None, name=None, args=(), kwargs={}):
        Process.__init__(self, group, target, name, args, kwargs)
        self.work_queue = work_queue
        self.result_queue = result_queue
        self.daemon = True  # 主线程退出  该线程也会退出
        # 为了兼容普通线程类模式
        self.mode = "default"
        self.mypsutil = None

    def run(self):
        def run(self):
            if self.mode == "default":
                self.run1()
            elif self.mode == "super":
                super().run()
            else:
                raise Exception("运行模式错误 请检查 default or super")

    def run1(self):
        pass

    def get_pids(self):
        """
        获取进程pid
        :return:
        """
        return self.pid

    def set_process_psutil_obj(self):
        self.mypsutil = MPsutil(self.get_pids())
